package com.zhu.tips;

import lombok.Data;

import java.io.*;

/**
 * 克隆一个对象并不会调用对象的构造方法。
 * 一般在使用new操作符创建一个对象的时候，一定会执行类的构造方法，在构造方法中可以做一些数据加载或者初始化的操作。
 * 然而，在实现了Cloneable接口的类中，重载clone方法产生新对象时，是不会执行类的构造方法的。
 * 原因很简单，在使用Object类的clone方法时，是从内存中直接复制二进制流，重新分配内存块给克隆对象，所以构造方法不被执行也在情理之中。
 */
/**
 * Created with IntelliJ IDEA.
 *
 * @Author: zhujiabao
 * @Date: 2022/02/21/15:46
 * @Description: 实现对象的克隆
 */
public class CloneTest {

    public static void main(String[] args) {
        Student liubei = new Student();
        liubei.setName("刘备");
        liubei.setAge(30);

        //new一个类，测试深克隆
        StudentClass studentClass = new StudentClass();
        studentClass.setStudentClass("studentClass---001");

        liubei.setSC(studentClass);

        Student guanyu = null;
        try {
            guanyu = liubei.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        System.out.println(liubei);

        guanyu.setName("关羽");
        guanyu.setAge(25);

        guanyu.getSC().setStudentClass("studentClass---002");

        System.out.println(liubei);
        System.out.println(guanyu);
    }

}

@Data
class Student implements Cloneable,Serializable{
    private static final long serialVersionUID = 1L;
    private String name;
    private int age;
    //对象属性
    public StudentClass sC;
    //构造方法
    public Student(){
        System.out.println("构造方法被调用");
    }
    //重写toString方法
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sC=" + sC +
                '}';
    }
    //重写clone方法
    /*@Override
    public Student clone() throws CloneNotSupportedException {
        Student student = (Student) super.clone();
//        student.sC = new StudentClass();
        student.sC = student.sC.clone();
        return student;
    }*/

    @Override
    protected Student clone() throws CloneNotSupportedException {
        Student student = null;

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(this);
            oos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        try {
            ObjectInputStream ois = new ObjectInputStream(bais);
            student = (Student)ois.readObject();
            ois.close();
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }

        return student;
    }
}

@Data
class StudentClass implements Cloneable, Serializable{
    private static final long serialVersionUID = 320551237720888204L;

    private String StudentClass;

    @Override
    public String toString() {
        return "StudentClass{" +
                "StudentClass='" + StudentClass + '\'' +
                '}';
    }
    //重写clone方法
    @Override
    public StudentClass clone() throws CloneNotSupportedException {
        return (StudentClass) super.clone();
    }
}
